/*
 * 文件名：RSA.java
 * 版权：Copyright Copyright by will_awoke
 * 描述：
 * 修改人：will_awoke
 * 修改时间：2014-8-7
 * 跟踪单号：
 * 修改单号：
 * 修改内容：
 */
package com.qbgs.security;


import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;

import javax.crypto.Cipher;

import org.apache.commons.lang.ArrayUtils;
import org.apache.log4j.Logger;


/**
 * 
 * @author will_awoke
 * @version 2014-8-7
 * @see RSA
 * @since
 */
public class RSA
{

    private PublicKey publicKey = null;

    private PrivateKey privateKey = null;

    private static final Logger logger = Logger.getLogger(RSA.class);

    /**
     * 
     * Description: 自动生成长度为1024BIT的公钥和私钥
     *  
     * @see
     */
    public void generator()
    {
        try
        {
            // 创建密匙对生成器
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            // 指定密匙长度（取值范围：512～2048）
            kpg.initialize(1024);
            // 生成密匙对，其中包含着一个公匙和一个私匙的信息
            KeyPair kp = kpg.genKeyPair();
            // 获得公匙
            publicKey = kp.getPublic();
            // 获得私匙
            privateKey = kp.getPrivate();
            logger.info("publicKey=" + publicKey);
            logger.info("privateKey=" + privateKey);
        }
        catch (NoSuchAlgorithmException e)
        {
            logger.error("NoSuchAlgorithmException:", e);
        }
    }

    /**
     * 
     * Description: 自动生成长度为length的公钥和私钥
     * 
     * @param length 
     * @see
     */
    public void generator(int length)
    {
        try
        {
            // 创建密匙对生成器
            KeyPairGenerator kpg = KeyPairGenerator.getInstance("RSA");
            // 指定密匙长度（取值范围：512～2048）
            kpg.initialize(length);
            // 生成密匙对，其中包含着一个公匙和一个私匙的信息
            KeyPair kp = kpg.genKeyPair();
            // 获得公匙
            publicKey = kp.getPublic();
            // 获得私匙
            privateKey = kp.getPrivate();
        }
        catch (NoSuchAlgorithmException e)
        {
            logger.error("NoSuchAlgorithmException:", e);
        }
    }

    /** 
     * 
     * Description: 将公钥和私钥保存在path路径的文件夹内
     * 
     * @param path 
     * @see
     */
    public void saveKeyForFile(String path)
    {
        FileOutputStream publicfos = null;
        ObjectOutputStream publicoos = null;
        FileOutputStream privatefos = null;
        ObjectOutputStream privateoos = null;
        try
        {
            // 保存公匙
            publicfos = new FileOutputStream(path + "/public_rsa_key.dat");
            publicoos = new ObjectOutputStream(publicfos);
            publicoos.writeObject(publicKey);

            // 保存私匙
            privatefos = new FileOutputStream(path + "/private_rsa_key.dat");
            privateoos = new ObjectOutputStream(privatefos);
            privateoos.writeObject(privateKey);
            publicfos.close();
            publicoos.close();
            privatefos.close();
            privateoos.close();

        }
        catch (FileNotFoundException e)
        {
            logger.error("FileNotFoundException:", e);
        }
        catch (IOException e)
        {
            logger.error("IOException:", e);
        }
    }

    /**
     * 
     * Description: 在path路径下的文件夹内读取公钥和私钥
     * 
     * @param path 
     * @see
     */
    public void readKeyFromFile(String path)
    {
        logger.info("RSA load securityKey from: " + path);
        
        FileInputStream publicfis = null;
        ObjectInputStream publicois = null;
        FileInputStream privatefis = null;
        ObjectInputStream privateois = null;
        try
        {
            // 读取公匙
            publicfis = new FileInputStream(path + "/public_rsa_key.dat");
            publicois = new ObjectInputStream(publicfis);
            publicKey = (PublicKey)publicois.readObject();

            // 读取私匙
            privatefis = new FileInputStream(path + "/private_rsa_key.dat");
            privateois = new ObjectInputStream(privatefis);
            privateKey = (PrivateKey)privateois.readObject();
            publicfis.close();
            publicois.close();
            privatefis.close();
            privateois.close();

        }
        catch (FileNotFoundException e)
        {
            logger.error("FileNotFoundException:", e);
        }
        catch (IOException e)
        {
            logger.error("IOException:", e);
        }
        catch (ClassNotFoundException e)
        {
            logger.error("ClassNotFoundException:", e);
        }
    }

    /**
     * 
     * Description: 得到公钥的BYTE数组
     * 
     * @return byte[]
     * @see
     */
    public byte[] getPublicKeyByteStream()
    {
        ByteArrayOutputStream baos = null;
        ObjectOutputStream oos = null;
        try
        {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(publicKey);
            baos.close();
            oos.close();

            return baos.toByteArray();
        }
        catch (IOException e)
        {
            logger.error("IOException:", e);
        }
        return null;

    }

    /**
     * 
     * Description: 得到公钥的字符串
     * 
     * @return String
     * @see
     */
    public String getPublicKeyForString()
    {
        ByteArrayOutputStream baos = null;
        ObjectOutputStream oos = null;

        try
        {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(publicKey);
            baos.close();
            oos.close();

            return RSAUtils.Bytes2HexString(baos.toByteArray());
        }
        catch (IOException e)
        {
            logger.error("IOException:", e);
        }
        return null;
    }

    /**
     * 
     * Description: 得到私钥的BYTE数组
     * 
     * @return byte[]
     * @see
     */
    public byte[] getPrivateKeyByteStream()
    {
        ByteArrayOutputStream baos = null;
        ObjectOutputStream oos = null;
        try
        {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(privateKey);
            baos.close();
            oos.close();

            return baos.toByteArray();
        }
        catch (IOException e)
        {
            logger.error("IOException:", e);
        }
        return null;
    }

    /**
     * 
     * Description: 得到私钥的字符串
     * 
     * @return String
     * @see
     */
    public String getPrivateKeyForString()
    {
        ByteArrayOutputStream baos = null;
        ObjectOutputStream oos = null;
        try
        {
            baos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(baos);
            oos.writeObject(privateKey);
            baos.close();
            oos.close();

            return RSAUtils.Bytes2HexString(baos.toByteArray());
        }
        catch (IOException e)
        {
            logger.error("IOException:", e);
        }
        return null;
    }

    /** 
     * 
     * Description: 通过byte数组来设置公钥
     * 
     * @param bytes 
     * @see
     */
    public void setPublicKeyByBytes(byte[] bytes)
    {
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;

        try
        {
            bais = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bais);
            publicKey = (PublicKey)ois.readObject();
            bais.close();
            ois.close();

        }
        catch (IOException e)
        {
            logger.error("IOException:", e);
        }
        catch (ClassNotFoundException e)
        {
            logger.error("ClassNotFoundException:", e);
        }
    }

    /**
     * 
     * Description: 通过String来设置公钥
     * 
     * @param pk 
     * @see
     */
    public void setPublicKeyByString(String pk)
    {
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
        try
        {
            bais = new ByteArrayInputStream(RSAUtils.HexString2Bytes(pk));
            ois = new ObjectInputStream(bais);
            publicKey = (PublicKey)ois.readObject();
            bais.close();
            ois.close();

        }
        catch (IOException e)
        {
            logger.error("IOException:", e);
        }
        catch (ClassNotFoundException e)
        {
            logger.error("ClassNotFoundException:", e);
        }
    }

    /**
     * 
     * Description: 通过byte来设置私钥
     * 
     * @param bytes 
     * @see
     */
    public void setPrivateKeyByBytes(byte[] bytes)
    {
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
        try
        {
            bais = new ByteArrayInputStream(bytes);
            ois = new ObjectInputStream(bais);
            privateKey = (PrivateKey)ois.readObject();
            bais.close();
            ois.close();

        }
        catch (IOException e)
        {
            logger.error("IOException:", e);
        }
        catch (ClassNotFoundException e)
        {
            logger.error("ClassNotFoundException:", e);
        }
    }

    /**
     * 
     * Description: 通过String来设置私钥
     * 
     * @param pk 
     * @see
     */
    public void setPrivateKeyByString(String pk)
    {
        ByteArrayInputStream bais = null;
        ObjectInputStream ois = null;
        try
        {
            bais = new ByteArrayInputStream(RSAUtils.HexString2Bytes(pk));
            ois = new ObjectInputStream(bais);
            privateKey = (PrivateKey)ois.readObject();
            bais.close();
            ois.close();

        }
        catch (IOException e)
        {
            logger.error("IOException:", e);
        }
        catch (ClassNotFoundException e)
        {
            logger.error("ClassNotFoundException:", e);
        }
    }

    /**
     * 
     * Description: 将明文加密成密文byte数组
     * 
     * @param encodeString
     * @return 
     * @see
     */
    public byte[] encryptModeForBytes(String encodeString)
    {
        try
        {
            // 定义RSA加密实例
            Cipher cipher = Cipher.getInstance("RSA");
            // 加密
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] bytes = encodeString.getBytes();
            byte[] encodedByteArray = new byte[] {};
            for (int i = 0; i < bytes.length; i += 100)
            {
                byte[] subarray = ArrayUtils.subarray(bytes, i, i + 100);
                byte[] doFinal = cipher.doFinal(subarray);
                encodedByteArray = ArrayUtils.addAll(encodedByteArray, doFinal);
            }
            return encodedByteArray;
        }
        catch (Exception e)
        {
            logger.error("Exception:", e);
        }
        return null;
    }

    /**
     * 
     * Description:将明文加密成密文字符串
     * 
     * @param encodeString
     * @return 
     * @see
     */
    public String encryptModeForString(String encodeString)
    {
        try
        {
            // 定义RSA加密实例
            Cipher cipher = Cipher.getInstance("RSA");
            // 加密
            cipher.init(Cipher.ENCRYPT_MODE, publicKey);
            byte[] bytes = encodeString.getBytes();
            byte[] encodedByteArray = new byte[] {};
            for (int i = 0; i < bytes.length; i += 100)
            {
                byte[] subarray = ArrayUtils.subarray(bytes, i, i + 100);
                byte[] doFinal = cipher.doFinal(subarray);
                encodedByteArray = ArrayUtils.addAll(encodedByteArray, doFinal);
            }
            return RSAUtils.Bytes2HexString(encodedByteArray);
        }
        catch (Exception e)
        {
            logger.error("Exception:", e);
        }
        return null;
    }

    /**
     * 
     * Description:将密文byte数组解密成明文字符串
     * 
     * @param decodeByteArray
     * @return String
     * @see
     */
    public String decryptModeFromBytes(byte[] decodeByteArray)
    {
        try
        {
            // 定义RSA解密实例
            Cipher cipher = Cipher.getInstance("RSA");
            // 解密
            cipher.init(Cipher.DECRYPT_MODE, privateKey);

            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < decodeByteArray.length; i += 128)
            {
                byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(decodeByteArray, i, i + 128));
                sb.append(new String(doFinal));
            }

            return sb.toString();
        }
        catch (Exception e)
        {
            logger.error("Exception:", e);
        }
        return null;
    }

    /**
     * 
     * Description: 将密文字符串解密成明文字符串
     * 
     * @param decodeString
     * @return String
     * @see
     */
    public String decryptModeFromString(String decodeString)
    {
        try
        {
            // 定义RSA解密实例
            Cipher cipher = Cipher.getInstance("RSA");
            // 解密
            cipher.init(Cipher.DECRYPT_MODE, privateKey);
            byte[] decodeByteArray = RSAUtils.HexString2Bytes(decodeString);
            StringBuilder sb = new StringBuilder();
            for (int i = 0; i < decodeByteArray.length; i += 128)
            {
                byte[] doFinal = cipher.doFinal(ArrayUtils.subarray(decodeByteArray, i, i + 128));
                sb.append(new String(doFinal));
            }

            return sb.toString();
        }
        catch (Exception e)
        {
            logger.error("Exception:", e);
        }
        return null;
    }

    /**
     * for test
     * @param args 
     * @see
     */
    public static void main(String[] args)
    {
        RSA ras = new RSA();
        //执行一次即可，重复执行 generator将导致此前生成的密钥丢失，生产环境严禁多次执行！
        /*ras.generator();
        String path = RSA.class.getClassLoader().getResource(
            "security").getPath();
        logger.info(path);
        ras.saveKeyForFile(path);*/
        //ras.readKeyFromFile(path);
        
        logger.info(ras.encryptModeForString("222222222222222222222222222222222222222"));
        logger.info(ras.encryptModeForString("222222222222222222222222222222222222222").length());
        logger.info(ras.encryptModeForString("222ssssssssssssssssssssssssssssssssssssssssssssssssssss"));
    }

}
